//! HTML表单处理模块
//!
//! 这个模块提供了对HTML表单的处理功能，包括表单解析、数据提取和表单验证

use crate::{DomNode, HtmlParser, HtmlParserError, NodeType};
use std::collections::HashMap;

/// 表单数据类型
#[derive(Debug, Clone, PartialEq)]
pub enum FormValueType {
    /// 文本值
    Text(String),
    /// 文件上传
    File {
        /// 文件名
        name: String,
        /// 文件类型
        content_type: String,
    },
    /// 复选框或者多选列表
    Multiple(Vec<String>),
    /// 空值
    Empty,
}

/// 表单提交方法
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FormMethod {
    /// GET方法
    Get,
    /// POST方法
    Post,
    /// PUT方法
    Put,
    /// DELETE方法
    Delete,
}

impl Default for FormMethod {
    fn default() -> Self {
        FormMethod::Get
    }
}

impl std::str::FromStr for FormMethod {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_uppercase().as_str() {
            "GET" => Ok(FormMethod::Get),
            "POST" => Ok(FormMethod::Post),
            "PUT" => Ok(FormMethod::Put),
            "DELETE" => Ok(FormMethod::Delete),
            _ => Err(format!("不支持的HTTP方法: {}", s)),
        }
    }
}

/// 表单编码类型
#[derive(Debug, Clone, PartialEq)]
pub enum FormEnctype {
    /// application/x-www-form-urlencoded
    UrlEncoded,
    /// multipart/form-data
    MultipartFormData,
    /// text/plain
    TextPlain,
}

impl Default for FormEnctype {
    fn default() -> Self {
        FormEnctype::UrlEncoded
    }
}

impl std::str::FromStr for FormEnctype {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_lowercase().as_str() {
            "application/x-www-form-urlencoded" => Ok(FormEnctype::UrlEncoded),
            "multipart/form-data" => Ok(FormEnctype::MultipartFormData),
            "text/plain" => Ok(FormEnctype::TextPlain),
            _ => Err(format!("不支持的编码类型: {}", s)),
        }
    }
}

/// HTML表单结构
#[derive(Debug, Clone)]
pub struct HtmlForm {
    /// 表单ID
    pub id: Option<String>,
    /// 表单名称
    pub name: Option<String>,
    /// 表单动作（提交地址）
    pub action: Option<String>,
    /// 表单提交方法
    pub method: FormMethod,
    /// 表单编码类型
    pub enctype: FormEnctype,
    /// 表单字段
    pub fields: HashMap<String, FormValueType>,
    /// 表单按钮
    pub buttons: Vec<FormButton>,
    /// 原始DOM节点引用
    pub dom_node: DomNode,
}

/// 表单按钮
#[derive(Debug, Clone)]
pub struct FormButton {
    /// 按钮类型
    pub button_type: ButtonType,
    /// 按钮名称
    pub name: Option<String>,
    /// 按钮值
    pub value: Option<String>,
    /// 按钮文本
    pub text: String,
    /// 是否禁用
    pub disabled: bool,
}

/// 按钮类型
#[derive(Debug, Clone, PartialEq)]
pub enum ButtonType {
    /// 提交按钮
    Submit,
    /// 重置按钮
    Reset,
    /// 普通按钮
    Button,
}

impl std::str::FromStr for ButtonType {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_lowercase().as_str() {
            "submit" => Ok(ButtonType::Submit),
            "reset" => Ok(ButtonType::Reset),
            "button" => Ok(ButtonType::Button),
            _ => Ok(ButtonType::Submit), // 默认为submit
        }
    }
}

impl HtmlForm {
    /// 从DOM节点创建表单
    pub fn from_node(node: &DomNode) -> Result<Self, HtmlParserError> {
        // 验证节点是否为表单
        if let NodeType::Element(tag) = &node.node_type {
            if tag != "form" {
                return Err(HtmlParserError::InvalidNode("节点不是表单元素".to_string()));
            }
        } else {
            return Err(HtmlParserError::InvalidNode("节点不是元素节点".to_string()));
        }

        // 获取表单属性
        let id = node.get_attribute("id").map(|s| s.to_string());
        let name = node.get_attribute("name").map(|s| s.to_string());
        let action = node.get_attribute("action").map(|s| s.to_string());

        // 获取表单方法
        let method = match node.get_attribute("method") {
            Some(method_str) => method_str.parse().unwrap_or_default(),
            None => FormMethod::default(),
        };

        // 获取表单编码类型
        let enctype = match node.get_attribute("enctype") {
            Some(enctype_str) => enctype_str.parse().unwrap_or_default(),
            None => FormEnctype::default(),
        };

        // 创建表单对象
        let mut form = HtmlForm {
            id,
            name,
            action,
            method,
            enctype,
            fields: HashMap::new(),
            buttons: Vec::new(),
            dom_node: node.clone(),
        };

        // 解析表单字段
        form.parse_fields(node);

        Ok(form)
    }

    /// 解析表单字段
    fn parse_fields(&mut self, node: &DomNode) {
        // 解析所有输入字段、选择框等
        let mut parser = HtmlParser::new(Default::default());

        // 查找所有input字段
        if let Ok(inputs) = parser.query_selector(node, "input") {
            for input in inputs {
                self.add_input_field(input);
            }
        }

        // 查找所有select字段
        if let Ok(selects) = parser.query_selector(node, "select") {
            for select in selects {
                self.add_select_field(select);
            }
        }

        // 查找所有textarea字段
        if let Ok(textareas) = parser.query_selector(node, "textarea") {
            for textarea in textareas {
                self.add_textarea_field(textarea);
            }
        }

        // 查找所有button元素
        if let Ok(buttons) = parser.query_selector(node, "button") {
            for button in buttons {
                self.add_button(button);
            }
        }

        // 查找input类型为submit、reset或button的元素
        if let Ok(buttons) = parser.query_selector(
            node,
            "input[type=submit], input[type=reset], input[type=button]",
        ) {
            for button in buttons {
                self.add_input_button(button);
            }
        }
    }

    // 添加input字段
    fn add_input_field(&mut self, node: &DomNode) {
        let name = match node.get_attribute("name") {
            Some(name) => name.to_string(),
            None => return, // 忽略没有name的字段
        };

        let input_type = node.get_attribute("type").unwrap_or("text");
        let value = node.get_attribute("value").unwrap_or("").to_string();
        let checked = node.get_attribute("checked").is_some();

        match input_type {
            "checkbox" => {
                if checked {
                    match self.fields.get_mut(&name) {
                        Some(FormValueType::Multiple(values)) => {
                            values.push(value);
                        }
                        _ => {
                            self.fields
                                .insert(name, FormValueType::Multiple(vec![value]));
                        }
                    }
                }
            }
            "radio" => {
                if checked {
                    self.fields.insert(name, FormValueType::Text(value));
                }
            }
            "file" => {
                self.fields.insert(
                    name,
                    FormValueType::File {
                        name: "".to_string(),
                        content_type: "".to_string(),
                    },
                );
            }
            // 忽略按钮类型，这些将单独处理
            "submit" | "reset" | "button" => {}
            // 处理其他类型的输入框
            _ => {
                if !value.is_empty() {
                    self.fields.insert(name, FormValueType::Text(value));
                } else {
                    self.fields.insert(name, FormValueType::Empty);
                }
            }
        }
    }

    // 添加select字段
    fn add_select_field(&mut self, node: &DomNode) {
        let name = match node.get_attribute("name") {
            Some(name) => name.to_string(),
            None => return, // 忽略没有name的字段
        };

        let multiple = node.get_attribute("multiple").is_some();
        let mut parser = HtmlParser::new(Default::default());

        if let Ok(options) = parser.query_selector(node, "option[selected]") {
            if !options.is_empty() {
                if multiple {
                    let values: Vec<String> = options
                        .iter()
                        .filter_map(|opt| {
                            opt.get_attribute("value")
                                .map(|v| v.to_string())
                                .or_else(|| Some(opt.text_content()))
                        })
                        .collect();

                    if !values.is_empty() {
                        self.fields.insert(name, FormValueType::Multiple(values));
                    } else {
                        self.fields.insert(name, FormValueType::Empty);
                    }
                } else {
                    // 单选，取第一个选中的选项
                    let value = options[0]
                        .get_attribute("value")
                        .map(|v| v.to_string())
                        .unwrap_or_else(|| options[0].text_content());

                    self.fields.insert(name, FormValueType::Text(value));
                }
            } else {
                // 如果没有选中的选项，选择第一个选项
                if let Ok(first_option) = parser.query_selector(node, "option:first-child") {
                    if !first_option.is_empty() {
                        let value = first_option[0]
                            .get_attribute("value")
                            .map(|v| v.to_string())
                            .unwrap_or_else(|| first_option[0].text_content());

                        self.fields.insert(name, FormValueType::Text(value));
                    } else {
                        self.fields.insert(name, FormValueType::Empty);
                    }
                } else {
                    self.fields.insert(name, FormValueType::Empty);
                }
            }
        }
    }

    // 添加textarea字段
    fn add_textarea_field(&mut self, node: &DomNode) {
        let name = match node.get_attribute("name") {
            Some(name) => name.to_string(),
            None => return, // 忽略没有name的字段
        };

        let value = node.text_content();
        self.fields.insert(name, FormValueType::Text(value));
    }

    // 添加按钮
    fn add_button(&mut self, node: &DomNode) {
        let button_type_str = node.get_attribute("type").unwrap_or("submit");
        let button_type = button_type_str.parse().unwrap_or(ButtonType::Submit);
        let name = node.get_attribute("name").map(|s| s.to_string());
        let value = node.get_attribute("value").map(|s| s.to_string());
        let text = node.text_content();
        let disabled = node.get_attribute("disabled").is_some();

        self.buttons.push(FormButton {
            button_type,
            name,
            value,
            text,
            disabled,
        });
    }

    // 添加input按钮
    fn add_input_button(&mut self, node: &DomNode) {
        let input_type = node.get_attribute("type").unwrap_or("submit");
        let button_type = match input_type {
            "submit" => ButtonType::Submit,
            "reset" => ButtonType::Reset,
            "button" => ButtonType::Button,
            _ => return, // 忽略其他类型
        };

        let name = node.get_attribute("name").map(|s| s.to_string());
        let value = node.get_attribute("value").map(|s| s.to_string());
        let text = value.clone().unwrap_or_else(|| "".to_string());
        let disabled = node.get_attribute("disabled").is_some();

        self.buttons.push(FormButton {
            button_type,
            name,
            value,
            text,
            disabled,
        });
    }

    /// 获取表单数据为URL编码字符串
    pub fn to_url_encoded(&self) -> String {
        let mut params = Vec::new();

        for (name, value) in &self.fields {
            match value {
                FormValueType::Text(text) => {
                    params.push(format!(
                        "{}={}",
                        urlencoding::encode(name),
                        urlencoding::encode(text)
                    ));
                }
                FormValueType::Multiple(values) => {
                    for val in values {
                        params.push(format!(
                            "{}={}",
                            urlencoding::encode(name),
                            urlencoding::encode(val)
                        ));
                    }
                }
                FormValueType::File { .. } => {
                    // URL编码不支持文件上传
                    // 在实际应用中，应该使用multipart/form-data
                }
                FormValueType::Empty => {
                    params.push(format!("{}=", urlencoding::encode(name)));
                }
            }
        }

        params.join("&")
    }

    /// 获取表单数据为JSON字符串
    pub fn to_json(&self) -> Result<String, serde_json::Error> {
        let mut map = serde_json::Map::new();

        for (name, value) in &self.fields {
            match value {
                FormValueType::Text(text) => {
                    map.insert(name.clone(), serde_json::Value::String(text.clone()));
                }
                FormValueType::Multiple(values) => {
                    let json_values: Vec<serde_json::Value> = values
                        .iter()
                        .map(|v| serde_json::Value::String(v.clone()))
                        .collect();
                    map.insert(name.clone(), serde_json::Value::Array(json_values));
                }
                FormValueType::File {
                    name: file_name, ..
                } => {
                    map.insert(name.clone(), serde_json::Value::String(file_name.clone()));
                }
                FormValueType::Empty => {
                    map.insert(name.clone(), serde_json::Value::Null);
                }
            }
        }

        serde_json::to_string(&map)
    }

    /// 验证表单是否有必填字段
    pub fn validate_required(&self, required_fields: &[&str]) -> Result<(), Vec<String>> {
        let mut missing = Vec::new();

        for field in required_fields {
            match self.fields.get(*field) {
                None => {
                    missing.push((*field).to_string());
                }
                Some(FormValueType::Text(text)) => {
                    if text.trim().is_empty() {
                        missing.push((*field).to_string());
                    }
                }
                Some(FormValueType::Multiple(values)) => {
                    if values.is_empty() {
                        missing.push((*field).to_string());
                    }
                }
                Some(FormValueType::Empty) => {
                    missing.push((*field).to_string());
                }
                _ => {}
            }
        }

        if missing.is_empty() {
            Ok(())
        } else {
            Err(missing)
        }
    }
}

// 创建一个内部辅助函数用于主要的表单提取逻辑
/// 提取页面中的所有表单（内部实现）
pub fn extract_forms_impl(
    parser: &HtmlParser,
    dom: &DomNode,
) -> Result<Vec<HtmlForm>, HtmlParserError> {
    let form_elements = parser.query_selector(dom, "form")?;
    let mut forms = Vec::new();

    for form_element in form_elements {
        if let Ok(form) = HtmlForm::from_node(form_element) {
            forms.push(form);
        }
    }

    Ok(forms)
}

impl HtmlParser {
    // 移除或注释掉此方法，我们将使用lib.rs中的实现
    /*
    /// 提取页面中的所有表单
    pub fn extract_forms(&self, dom: &DomNode) -> Result<Vec<HtmlForm>, HtmlParserError> {
        let form_elements = self.query_selector(dom, "form")?;
        let mut forms = Vec::new();

        for form_element in form_elements {
            if let Ok(form) = HtmlForm::from_node(form_element) {
                forms.push(form);
            }
        }

        Ok(forms)
    }
    */

    /// 根据ID或名称查找表单
    pub fn find_form(
        &self,
        dom: &DomNode,
        id_or_name: &str,
    ) -> Result<Option<HtmlForm>, HtmlParserError> {
        // 先按ID查找
        let selector = format!("form#{}", id_or_name);
        let forms_by_id = self.query_selector(dom, &selector)?;

        if !forms_by_id.is_empty() {
            return HtmlForm::from_node(&forms_by_id[0]).map(Some);
        }

        // 再按名称查找
        let selector = format!("form[name=\"{}\"]", id_or_name);
        let forms_by_name = self.query_selector(dom, &selector)?;

        if !forms_by_name.is_empty() {
            return HtmlForm::from_node(&forms_by_name[0]).map(Some);
        }

        Ok(None)
    }
}
